// Generic function pump, used by various applications.
// Copyright 2006 (C) Ralph Thomas

#ifndef MISSION_FUNCTION_PUMP_H
#define MISSION_FUNCTION_PUMP_H

#include <boost/bind.hpp>
#include <adobe/dictionary.hpp>
#include <adobe/name.hpp>
#include <binder.hpp>
#include <vector>

namespace app {
	//
	/// The function adapter is a wrapper that takes
	/// function and make it appear as a data pump
	/// that can be invoked (e.g.: from a button).
	//
	struct function_adapter_t : public adobe::binder_t {
		typedef boost::function<void (const adobe::dictionary_t&)>	function_t;
		virtual ~function_adapter_t();
		//
		// Implementation of methods from binder.
		//
		virtual void set( const adobe::any_regular_t& val );
		virtual void set_signals(
			const adobe::sheet_t::monitor_value_t& monitor_value,
			const adobe::sheet_t::monitor_active_t& monitor_active );
		virtual void substitute( const adobe::name_t& name, const adobe::any_regular_t& val );
		virtual void invoke();
		virtual adobe::binder_ptr_t copy() const
		{
			return adobe::binder_ptr_t( new function_adapter_t( sheet_m, func_m, dict_m ) );
		}
		//
		/// This is a factory function that can be given to
		/// the client_assembler (once bound up with the
		/// function to call). So if you have a function "f"
		/// that takes a dictionary_t, then you would make
		/// a factory function like so:
		///
		///  boost::bind( &function_adapter_t::create, &f _1 )
		///
		/// \param	f	the function to call on invoke.
		/// \param	sheet	the sheet to bind to.
		/// \param	dict	the dictionary coming from the
		///			Eve file.
		//
		static adobe::binder_ptr_t create( const function_t& f, adobe::sheet_t& sheet, const adobe::dictionary_t& dict ) {
			return adobe::binder_ptr_t( new function_adapter_t( sheet, f, dict ) );
		}
	  private:
		typedef std::vector<adobe::binder_helper_t*> binder_list_t;
		//
		/// The function_adapter_t takes a function and invokes it
		/// when the binder adapter is invoked.
		///
		/// \param	f	the function to call when invoked.
		//
		function_adapter_t( adobe::sheet_t& sheet, const function_t& f, const adobe::dictionary_t& dict );
		//
		/// Reference to a sheet (used to create copies).
		//
		adobe::sheet_t& sheet_m;
		//
		/// We keep a dictionary of values which are updated by
		/// a list of binder_helper_ts created from the parameter
		/// dictionary we are given in our ctor.
		//
		adobe::dictionary_t values_m;
		//
		/// The list of binder_helpers that keep our value dictionary
		/// up-to-date.
		//
		binder_list_t binders_m;
		//
		/// The function to call when invoked.
		//
		function_t func_m;
		//
		/// The original source dictionary (used to create copies).
		//
		adobe::dictionary_t dict_m;
	};
};

#endif

